using System;
using System.Collections.Generic;
using System.Text;

namespace Yaml.Grammar
{
	/// <summary>
	/// Wrapper for reading in a text file.
	/// </summary>
	public class TextInput : IParserInput<char>
	{
		/// <summary>
		/// Input text.
		/// </summary>
		private string _inputText;

		/// <summary>
		/// List of indexes for the line breaks within the text.
		/// </summary>
		private List<int> _lineBreaks;

		/// <summary>
		/// Constructor for the TextInput class.
		/// Parses the input text to build a list of linebreaks for the entire file.
		/// </summary>
		/// <param name="text">The input text.</param>
		public TextInput(string text)
		{
			this._inputText = text;

			_lineBreaks = new List<int>();
			_lineBreaks.Add(0);
			for (int index = 0; index < this._inputText.Length; index++)
			{
				if (this._inputText[index] == '\n')
				{
					_lineBreaks.Add(index);
				}
			}
		}

		/// <summary>
		/// The length of the string.
		/// </summary>
		public int Length
		{
			get { return this._inputText.Length; }
		}

		/// <summary>
		/// Is the pos past the end of the input text?
		/// </summary>
		/// <param name="pos">position we're inquiring about.</param>
		/// <returns>bool</returns>
		public bool HasInput(int pos)
		{
			return pos < this._inputText.Length;
		}

		/// <summary>
		/// Return the symbol at the current position.
		/// </summary>
		/// <param name="pos">current position</param>
		/// <returns>char</returns>
		public char GetInputSymbol(int pos)
		{
			return this._inputText[pos];
		}

		/// <summary>
		/// Returns the line and column for the passed in position within the text.
		/// </summary>
		/// <param name="pos">char offset within the text.</param>
		/// <param name="line">line number output</param>
		/// <param name="col">column output</param>
		public void GetLineColumnNumber(int pos, out int line, out int col)
		{
			col = 1;
			for (line = 1; line < _lineBreaks.Count; line++)
			{
				if (_lineBreaks[line] > pos)
				{
					col = pos - _lineBreaks[line - 1];
					break;
				}
			}
		}

		public string GetSubstring(int start, int length)
		{
			return this._inputText.Substring(start, length);
		}

		public string FormatErrorMessage(int position, string message)
		{
			int line;
			int col;
			GetLineColumnNumber(position, out line, out col);
			string ch = HasInput(position) ? " '" + GetInputSymbol(position) + "'" : null;
			return String.Format("Line {0}, Col {1}: {2}{3}", line, col, message, ch);
		}
	}
}
